package com.zwy.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zwy.constants.RedisConst;
import com.zwy.constants.SecurityConst;
import com.zwy.domain.entity.*;
import com.zwy.mapper.PermissionMapper;
import com.zwy.mapper.RoleMapper;
import com.zwy.mapper.RolePermissionMapper;
import com.zwy.mapper.UserRoleMapper;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zwy
 * @version 1.0
 * @description: JwtUtils
 * @date 2025/9/18 11:57
 * @action jwt工具类
 *JWT创建功能
 * createJwt: 创建JWT令牌
 * expireTime: 计算JWT过期时间
 * JWT解析与验证功能
 * resolveJwt: 解析和验证JWT令牌
 * invalidateJwt: 使JWT令牌失效
 * Token处理功能
 * convertToken: 处理请求头token格式
 * isInvalidToken: 检查令牌是否已失效
 * deleteToken: 删除令牌
 * 用户信息提取功能
 * toId: 从JWT中提取用户ID
 * toUser: 将JWT转换为UserDetails对象
 * 权限管理功能
 * getAuthorities: 获取用户权限列表
 */
@Component
public class JwtUtils {
    @Value("${spring.security.jwt.key}")
    private String key;
    @Value("${spring.security.jwt.expire}")
    private int expire;
    @Resource
    private RedisCache redisCache;

    /**
     * 创建jwt
     * @param uuid 唯一标识
     * @param details 用户详情
     * @param id 用户id
     * @param username 用户名
     * @return jwt
     */
    public String createJwt(String uuid, UserDetails details,Long id,String  username){
        Algorithm algorithm = Algorithm.HMAC256(key);
        Date expireTime = expireTime();
        //当前时间
        Date currentTime = new Date();
        String jwt = JWT.create()
                .withJWTId(uuid)
                .withSubject(details.getUsername())
                .withClaim("id",id)
                .withClaim("username",username)
                .withIssuedAt(currentTime)
                .withExpiresAt(expireTime)
                .sign(algorithm);
        //将jwt保存到redis中
        redisCache.setCacheObject(RedisConst.JWT_WHITE_LIST + uuid, jwt, expire, TimeUnit.DAYS);

        return jwt;
    }
    /**
     * 计算到期时间
     * @return 到期时间
     */
    public Date expireTime(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR,expire  * 24);
        return calendar.getTime();
    }
    /**
     * 解析jwt
     * @param headerToken 请求头中的token
     * @return 解析后的jwt
     */
    public DecodedJWT resolveJwt(String headerToken){
        String token = this.convertToken(headerToken);
        if (token == null) return null;
        Algorithm algorithm = Algorithm.HMAC256(key);
        JWTVerifier jwtverifier = JWT.require(algorithm).build();
        try {
            //是否合法，不合法会抛出一个运行时异常（需要自己捕获）
            DecodedJWT verify = jwtverifier.verify(token);
            //如果不在白名单中，说明令牌是无效的

            if(this.isInvalidToken(verify.getId()))
                return null;
            Date expiresAt = verify.getExpiresAt();
            //判断是否过期
            return new Date().after(expiresAt) ? null : verify;


        } catch (JWTVerificationException e) {
            return null;
        }


    }
    /**
     * 处理请求头中的token
     * @param headerToken 请求头中的token
     * @return 处理后的token
     */
    private String convertToken(String headerToken){
        if(headerToken == null || !headerToken.startsWith("Bearer ")){
            return null;
        }
        return headerToken.substring(7);
    }
    /**
     * 是否是一个过期的令牌
     *
     */
    public boolean isInvalidToken(String uuid){
//        如果在白名单中，说明令牌是有效的，进行空值判断
        return !Boolean.TRUE.equals(redisCache.isHasKey(RedisConst.JWT_WHITE_LIST + uuid));
    }

    public UserDetails toUser(DecodedJWT jwt) {
        Map<String, Claim> claims = jwt.getClaims();
        List<String> listStr = getAuthorities(jwt.getClaim("id").asLong());
        List<SimpleGrantedAuthority> collect = listStr.stream().map(SimpleGrantedAuthority::new).toList();

        return new LoginUser()
                .setUser
                        (
                                new User()
                                        .setId(toId(jwt))
                                        .setUsername(jwt.getClaim("username").asString())
                        )
                .setAuthorities(collect);

    }
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private RolePermissionMapper rolePermissionMapper;
    @Resource
    private PermissionMapper permissionMapper;
    /**
     * 获取用户权限列表
     * @param userId 用户id
     * @return 权限列表
     */
    private List<String> getAuthorities(Long userId){
        //查询用户角色
        List<UserRole> userRoles = userRoleMapper.selectList(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId));
        List<Long> roleIds = userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
        List<Role> roles = roleIds.isEmpty() ? Collections.emptyList() : roleMapper.selectBatchIds(roleIds);
        if(roles.isEmpty()){
            return Collections.emptyList();
        }else {
            //查询权限关系表
            List<RolePermission> rolePermissions = rolePermissionMapper.selectBatchIds(roles.stream().map(Role::getId).toList());
            //查询角色权限
            List<Long> pIds = rolePermissions.stream().map(RolePermission::getPermissionId).toList();
            List<Permission> permissions = permissionMapper.selectBatchIds(pIds);
            //组合角色，权限
            List<String> list = permissions.stream().map(Permission::getPermissionKey).collect(Collectors.toList());
            roles.forEach(role -> list.add(SecurityConst.ROLE_PREFIX + role.getRoleName()));
            list.addAll(roles.stream().map(Role::getRoleKey).toList());
            return list;
        }
    }
    /**
     * 从jwt中提取用户id
     * @param jwt 解析后的jwt
     * @return 用户id
     */
    public Long toId(DecodedJWT jwt){
        Map<String,Claim> claims = jwt.getClaims();
        return claims.get("id").asLong();

    }
    /**
     *让jwt令牌失效
     */
    public boolean invalidateJwt(String headerToken){
        String token = this.convertToken(headerToken);
        if(token == null) return false;

        // 验证令牌
        Algorithm algorithm = Algorithm.HMAC256(key);
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();
        try {
            DecodedJWT jwt = jwtVerifier.verify(token);
            String id = jwt.getId();
            return deleteToken(id);
        } catch (JWTVerificationException e) {
            return false;
        }
    }
    private boolean deleteToken(String uuid){
        //token 是否失效
        if(this.isInvalidToken(uuid)) return false;
        // 删除
        redisCache.deleteObject(RedisConst.JWT_WHITE_LIST + uuid);
        return true;
    }
}
